//-------------------
//--test ADC function
//-------------------

#define F_CPU 7372800UL

#include<avr/io.h>
#include<util/delay.h>
#include<avr/interrupt.h>


#define in_Single 0
#define Vref 3000
#define LED PORTA
#define uint16	unsigned int
#define uint32	unsigned long
#define uint8	unsigned char
#define int8	signed char
#define int16	signed int
#define int32	signed long

unsigned int threshold = 0x6000;
unsigned char cnt;
int32 sample[8];
int32 spec[8];


//=================================================
//===this is for debug , UART output to monintor===
//=================================================

void U_32(signed long read){
	uint32 read32;
	unsigned char ascii;
	unsigned char asciih;
	unsigned char asciil;

	read32 = read;
	ascii = read32>>24;
			asciih = ascii>>4;
			asciil = ascii<<4;
			asciil>>=4;

			while(!(UCSR0A&(1<<UDRE0)));
			if (asciih<0x0a)
				 UDR0 = (asciih + 0x30);			//123456789
			 else UDR0 = (asciih + 0x37);		//abcde

			while(!(UCSR0A&(1<<UDRE0)));
			 if (asciil<0x0a)
				 UDR0 = (asciil + 0x30);			//123456789
			 else UDR0 = (asciil + 0x37);		//abcde


				ascii = read32>>16;
						asciih = ascii>>4;
						asciil = ascii<<4;
						asciil>>=4;

						while(!(UCSR0A&(1<<UDRE0)));
						if (asciih<0x0a)
							 UDR0 = (asciih + 0x30);			//123456789
						 else UDR0 = (asciih + 0x37);		//abcde

						while(!(UCSR0A&(1<<UDRE0)));
						 if (asciil<0x0a)
							 UDR0 = (asciil + 0x30);			//123456789
						 else UDR0 = (asciil + 0x37);		//abcde


							ascii = read32>>8;
									asciih = ascii>>4;
									asciil = ascii<<4;
									asciil>>=4;

									while(!(UCSR0A&(1<<UDRE0)));
									if (asciih<0x0a)
										 UDR0 = (asciih + 0x30);			//123456789
									 else UDR0 = (asciih + 0x37);		//abcde

									while(!(UCSR0A&(1<<UDRE0)));
									 if (asciil<0x0a)
										 UDR0 = (asciil + 0x30);			//123456789
									 else UDR0 = (asciil + 0x37);		//abcde


											ascii = read32;
													asciih = ascii>>4;
													asciil = ascii<<4;
													asciil>>=4;

													while(!(UCSR0A&(1<<UDRE0)));
													if (asciih<0x0a)
														 UDR0 = (asciih + 0x30);			//123456789
													 else UDR0 = (asciih + 0x37);		//abcde

													while(!(UCSR0A&(1<<UDRE0)));
													 if (asciil<0x0a)
														 UDR0 = (asciil + 0x30);			//123456789
													 else UDR0 = (asciil + 0x37);		//abcde



}

//=================================================
//=================================================


unsigned char read_adc(void){							// 8 bit single end ADC function, using polling
	unsigned char data;
	ADMUX = (1<<REFS1)|(1<<REFS0)|(1<<ADLAR);			// use internal 2.56V Vref, left align, ADC0, no amplify
	ADCSRA = (1<<ADSC)|(1<<ADEN)|(1<<ADPS1);			// ask for one convert
	while(!(ADCSRA&(1<<ADIF)));							// wait for finish one convert
	ADCSRA |=(1<<ADIF);									// software clear
	data = ADCH;										// read only first 8 bit
	return data;
}



//=======================================================================================================================
//==============f(m) = sigmaN(   Xk * cos(pi/n* m *(K+1/2))  )		// n = 16, use matlab to get the coefficient
//=======================================================================================================================

// i think better to use fast DCT
// with reference to : http://www.geocities.com/ssavekar/dct.htm
// input: uint8 sample[8] time domain sample
// output:uint16 spec[8] frequency domain sequency ordered
// sampling rate 2K, so divide 1K range to 8 interval, assume drum and voice's frequency located mainly at the first two interval
void cal_beat(int32 *sample, int32 *spec){
	int32 temp[14];
	temp[0] = sample[0]+ sample[7];
	temp[4] = sample[0]- sample[7];
	temp[1] = sample[1]+ sample[6];
	temp[5] = sample[1]- sample[6];
	temp[2] = sample[2]+ sample[5];
	temp[6] = sample[2]- sample[5];
	temp[3] = sample[3]+ sample[4];
	temp[7] = sample[3]- sample[4];

	temp[8] = temp[0] + temp[3];
	temp[10] = temp[0] - temp[3];
	temp[9] = temp[1] + temp[2];
	temp[11] = temp[1] - temp[2];

	temp[12] = temp[8] + temp[9];
	temp[13] = temp[8] - temp[9];


	spec[0] = (temp[12])*181;
	spec[4] = (temp[13])*181;
	spec[2] = (temp[10])*236 + (temp[11])*98;
	spec[6] = (temp[10])*98 - (temp[11])*236;
	spec[1] = (temp[4])*251 + (temp[5])*213 + (temp[6])*142 + (temp[7])*50;
	spec[3] = (temp[4])*213 - (temp[5])*50 - (temp[6])*251 - (temp[7])*142;
	spec[5] = (temp[4])*142 - (temp[5])*251 + (temp[6])*50 + (temp[7])*213;
	spec[7] = (temp[4])*50 - (temp[5])*142 + (temp[6])*213 - (temp[7])*251;

	unsigned char count;
	for(count = 0; count<8; count++){
		if(spec[count]<0)spec[count]=-spec[count];
	}

}


void lightled(int32 *spec){
	uint8 count;
	for(count=0;count<8;count++){
		if(spec[count]>threshold){
			PORTA |= _BV(count);
		}
		else PORTA &= ~_BV(count);
	}
	/*
	//=======================================================
	for(count = 0; count<8; count++){
		while(!(UCSR0A&(1<<UDRE0)));
		UDR0 = 't';
		while(!(UCSR0A&(1<<UDRE0)));
		UDR0 = ':';
		U_32(sample[count]);
		while(!(UCSR0A&(1<<UDRE0)));
		UDR0 = ' ';
	}


	for(count = 0; count<8; count++){
j		while(!(UCSR0A&(1<<UDRE0)));
		UDR0 = 'f';
		while(!(UCSR0A&(1<<UDRE0)));
		UDR0 = ':';
		U_32(spec[count]);
		while(!(UCSR0A&(1<<UDRE0)));
		UDR0 = ' ';
	}

	//==========================================================
*/
	TIMSK&=~_BV(OCIE0);
	TIMSK|=_BV(OCIE1A);

}


void Timer0Init(void)
{
	TCCR0 = _BV(WGM01)|_BV(CS02);						//1/64
	OCR0  = 0x39;										// F_CPU
	TIMSK|=_BV(OCIE0);
}

void Timer1Init(void){
	TCCR1A=0;
	TCCR1B=_BV(WGM12)|_BV(CS10)|_BV(CS11);				// 1/64
	OCR1A=0x2D00;										//F_CPU/64 / 10
}


ISR(TIMER1_COMPA_vect){
	TIMSK &= ~_BV(OCIE1A);
	TIMSK |= _BV(OCIE0);
}


ISR(TIMER0_COMP_vect)
{
	sample[cnt] = read_adc();
	//*cnt += 1;
	//unsigned char count;
	cnt ++;

	if (cnt == 8){
		cli();
		cnt = 0;
		cal_beat(sample, spec);
		lightled(spec);
		sei();
	}
}



int main(void){
	cli();

	DDRA = 0xff;
	cnt = 0;

	UCSR0B = 0;

	UBRR0L = 3;
	UBRR0H = 0x00;							// Baud Rate 115200

	UCSR0A = 0;
	UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
	UCSR0B = (1<<TXEN0);					// 8 bit char

	Timer0Init();
	Timer1Init();

	sei();
	while(1);
	return 0;
}






/*

int main(void){

//=============================================================
	unsigned char ADC_SingleEnded;
	unsigned char cnt;
	unsigned char sample9;
	signed char data[9];
	signed int spec[9];

	DDRF = 0xFE;										// single end ADC0
	PORTF = 0xFE;
	DDRA = 0xff;										// output digital 8 bit to led
	ADCSRA = (1<<ADEN)|(1<<ADPS1);						// 1/64 frequency, enable ADC work

	sample16 = 0;

	while(1){
		data[sample9] = read_adc(0);
		sample9++;
		if(sample9 == 9){
			sample9 = 0;
			calbeat(data,spec);
		}
		else{
			for(cnt = 0; cnt<5; cnt++)_delay_us(100);		// wait for 0.5ms, sampling frequency is 2K
		}

	}
	return 0;
//===============================================================



	DDRF = 0xFE;
	PORTF = 0xFE;
	DDRA = 0xFF;


	UCSR0B = 0;

	UBRR0L = 3;
	UBRR0H = 0x00;							// Baud Rate 115200

	UCSR0A = 0;
	UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
	UCSR0B = (1<<TXEN0);					// 8 bit char


	int32 sample[8];

	int32 spec[8];

	uint8 cnt;


	while(1){
		for(cnt = 0; cnt<5; cnt++){
			_delay_ms(30);
		}

		for(cnt = 0; cnt<8; cnt++){
			sample[cnt] = read_adc();
			_delay_ms(0.45);
		}
		cal_beat(sample, spec);
		lightled(spec);



		for(cnt = 0; cnt<8; cnt++){
			while(!(UCSR0A&(1<<UDRE0)));
			UDR0 = 't';
			while(!(UCSR0A&(1<<UDRE0)));
			UDR0 = ':';
			U_32(sample[cnt]);
			while(!(UCSR0A&(1<<UDRE0)));
			UDR0 = ' ';
		}


		for(cnt = 0; cnt<8; cnt++){
			while(!(UCSR0A&(1<<UDRE0)));
			UDR0 = 'f';
			while(!(UCSR0A&(1<<UDRE0)));
			UDR0 = ':';
			U_32(spec[cnt]);
			while(!(UCSR0A&(1<<UDRE0)));
			UDR0 = ' ';
		}

//		while(1);




	}



return 0;
}









void calbeat(signed char *data, signed int *spec)

		uint16 threshold = 0x9000;

		//--------------process data array use fast walsh transform------------
		//recursively separate array[0:x-1]=> sub0=array[0:x/2-1] and sub1=array[(x/2 : x-1 ]
		//sub0[i]= sub0[i]+ sub1[i]; sub1[i]=sub1[i]-sub0[i]
		//recursive process subarray
		//----------------------------------------------------------------------


		uint8 ele_sub = WINDOW;				// #elements of subarrays
		uint8 hele_sub = (ele_sub/2);		// #half of elements
		uint8 num_sub = 1;					// number of subarrays

		uint8 i,j;
		uint8  index1;	uint8  index2;
		uint16 temp1;	uint16 temp2;

		uint8 degree = DEGREE;				// we process 16 datas, so WINDOW = 16, DEGREE = 4
		uint8 sub_start = 0;


		while(degree--){
			sub_start = 0;
			for(i=0; i<num_sub; i++){
				for(j= 0;j<hele_sub; j++){
					index1 = sub_start + j;		index2 = index1 + hele_sub;
					temp1 = data[index1];		temp2 = data[index2];
					data[index1] = temp1 + temp2;
					data[index2] = temp1 - temp2;
				}
				sub_start += ele_sub;
			}
			num_sub<<=1;
			ele_sub>>=1;	hele_sub>>=1;
		}

		//------------extract frequency---------------------------------------
		// reorder the data according to the frequency sequency
		// Reorder[16] =  {0 15 7 8 3 12 4 11 1 14 6 9 2 13 5 10}
		//--------------------------------------------------------------------

		//reorder
		uint16 temp[WINDOW];

		for(i =0; i<WINDOW; i++)
			temp[Reorder[i]] = data[i];

		for(i =0; i<WINDOW; i++)
			data[i] = temp[i];


		//compute frequency component, throw away data[0], and add merge intervals to one component
		uint16 freq[8];
		for(i=0; i<(WINDOW/2); i++)
			freq[i] = temp[i<<1]+ temp[(i<<1)+1];




//#define WINDOW 	16
//#define DEGREE 	4

//unsigned char Reorder[16] =  {0,15,7,8,3,12,4,11,1,14,6,9,2,13,5,10};
//int16 cos[9] = {541, 441, 288, 1, -1, -288, -441, -541, -576};



*/
